/*
 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */
package java.lang.reflect;

import java.lang.annotation.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import sun.reflect.annotation.AnnotationSupport;


public final class Parameter implements AnnotatedElement {

    private final String name;             // 参数名称, 正常编译得到: arg0 arg1
    private final int modifiers;
    private final Executable executable;
    private final int index;


    Parameter(String name,
              int modifiers,
              Executable executable,
              int index) {
        this.name = name;
        this.modifiers = modifiers;
        this.executable = executable;
        this.index = index;
    }


    public boolean equals(Object obj) {
        if(obj instanceof Parameter) {
            Parameter other = (Parameter)obj;
            return (other.executable.equals(executable) &&
                    other.index == index);
        }
        return false;
    }


    public int hashCode() {
        return executable.hashCode() ^ index;
    }


    public String toString() {
        final StringBuilder sb = new StringBuilder();
        final Type type = getParameterizedType();
        final String typename = type.getTypeName();

        sb.append(Modifier.toString(getModifiers()));

        if(0 != modifiers)
            sb.append(' ');

        if(isVarArgs())
            sb.append(typename.replaceFirst("\\[\\]$", "..."));
        else
            sb.append(typename);

        sb.append(' ');
        sb.append(getName());

        return sb.toString();
    }


    /**
     * 返回声明该参数对象的可执行文件
     */
    public Executable getDeclaringExecutable() {
        return executable;
    }


    /**
     * 返回修饰该参数对象修饰符的整数形式，使用 Modifier 类对其进行解码
     */
    public int getModifiers() {
        return modifiers;
    }

    /**
     * 返回参数对象名称
     * 正常编译得到: arg0 arg1
     * 加入-parameters后编译得到: key value
     */
    public String getName() {
        if(name == null || name.equals(""))
            return "arg" + index;
        else
            return name;
    }

    String getRealName() {
        return name;
    }


    /**
     * 返回一个类型对象，该对象表示该参数对象表示的泛型参数的类型 (保留泛型)
     */
    public Type getParameterizedType() {
        Type tmp = parameterTypeCache;
        if (null == tmp) {
            tmp = executable.getAllGenericParameterTypes()[index];
            parameterTypeCache = tmp;
        }
        return tmp;
    }

    /**
     * 返回一个 Class 对象，该 Class 对象表示该参数对象表示的声明参数的类型 (擦除泛型)
     */
    public Class<?> getType() {
        Class<?> tmp = parameterClassCache;
        if (null == tmp) {
            tmp = executable.getParameterTypes()[index];
            parameterClassCache = tmp;
        }
        return tmp;
    }

    private transient volatile Type parameterTypeCache = null;

    /**
     * 获取到对应的形参类型
     */
    public AnnotatedType getAnnotatedType() {
        return executable.getAnnotatedParameterTypes()[index];
    }


    /**
     * 如果该参数对象存在指定类型的注解，则返回该注解，否则返回 null
     */
    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
        Objects.requireNonNull(annotationClass);
        return annotationClass.cast(declaredAnnotations().get(annotationClass));
    }

    /**
     * 如果该参数对象存在指定类型的注解，则返回该注解，否则返回 null
     */
    public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
        return getAnnotation(annotationClass);
    }

    /**
     * 如果该参数对象存在指定类型的注解，则返回该注解数组，否则返回 null
     * getAnnotationsByType() 方法与 getAnnotation() 方法的区别在于：
     * getAnnotationsByType() 方法会检查修饰该参数对象的注解是否为可重复类型注解，如果是则会返回修饰该参数对象的一个或多个注解
     * 当声明为可重复类型注解后，如果参数注解仍为一个，则 getAnnotation() 方法会正常返回，如果参数注解为多个，则 getAnnotation() 方法会返回 null
     */
    @Override
    public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
        Objects.requireNonNull(annotationClass);
        return AnnotationSupport.getDirectlyAndIndirectlyPresent(declaredAnnotations(), annotationClass);
    }

    /**
     * 如果该参数对象存在指定类型的注解，则返回该注解数组，否则返回null
     */
    @Override
    public <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
        return getAnnotationsByType(annotationClass);
    }

    /**
     * 返回该参数对象上的所有注解，如果没有注解，则返回空数组
     */
    public Annotation[] getAnnotations() {
        return getDeclaredAnnotations();
    }

    /**
     * 返回该参数对象上的所有注解，如果没有注解，则返回空数组
     */
    public Annotation[] getDeclaredAnnotations() {
        return executable.getParameterAnnotations()[index];
    }

    /**
     * 如果该参数对象表示 可变参，则返回 true，否则为 false
     */
    public boolean isVarArgs() {
        return executable.isVarArgs() &&
                index == executable.getParameterCount() - 1;
    }

    /**
     * 如果该参数对象根据类文件能获取到名称，则返回 true，否则为 false
     * 当我们带上 -parameters 参数时，该参数对象就有了名称
     */
    public boolean isNamePresent() {
        return executable.hasRealParameterData() && name != null;
    }

    /**
     * 如果该参数对象为隐式参数，则返回 true，否则为 false
     */
    public boolean isImplicit() {
        return Modifier.isMandated(getModifiers());
    }

    /**
     * 如果该参数对象为合成参数，则返回 true，否则为 false
     */
    public boolean isSynthetic() {
        return Modifier.isSynthetic(getModifiers());
    }


    private transient volatile Class<?> parameterClassCache = null;














    private transient Map<Class<? extends Annotation>, Annotation> declaredAnnotations;

    private synchronized Map<Class<? extends Annotation>, Annotation> declaredAnnotations() {
        if(null == declaredAnnotations) {
            declaredAnnotations =
                new HashMap<Class<? extends Annotation>, Annotation>();
            Annotation[] ann = getDeclaredAnnotations();
            for(int i = 0; i < ann.length; i++)
                declaredAnnotations.put(ann[i].annotationType(), ann[i]);
        }
        return declaredAnnotations;
   }

}
